package com.jpragma.flexutils {
	import flash.events.StatusEvent;
	import flash.net.LocalConnection;
	import flash.utils.getTimer;
	
	import org.spicefactory.lib.logging.LogEvent;
	import org.spicefactory.lib.logging.Logger;
	import org.spicefactory.lib.logging.impl.AbstractAppender;

	/**
	 * This class can be used as spicelib log appender
	 * @see http://spicefactory.org/...
	 * and allows to write log messages to LocalConnection consumed by another application.
	 * JPLogViewer is Adobe AIR UI application that colorizes and displays these messages.
	 * @see http://..... 
	 * @example The following snippet shows parsley logger configuration that uses LocalConnectionAppender:
	 * <listing version="3.0">
	 * 	<object id="localConnectionAppender" type="LocalConnectionAppender">
	 *		<property name="connectionName" value="_loggerConnection"/>
	 *		<property name="logStackTrace" value="true"/>
	 *		<property name="reconnectInterval" value="5000"/>
	 *  </object>
	 * 
	 *  <log:factory id="logFactory" root-level="trace" context="true">
	 *		<log:logger name="com.rbccm" level="debug"/>
	 *		<log:appender ref="localConnectionAppender" threshold="trace"/>
	 *  </log:factory>
	 * </listing>
	 * 
	 * @author Isaac Levin
	 */
	public class LocalConnectionAppender extends AbstractAppender {
		private var _connectionName:String = "_loggerConnection";
		private var _receiverMethodName:String = "logMessage";
		private var _logStackTrace:Boolean = false;
		private var _reconnectInterval:int = 10000;
		private var _lastSendSuccessful:Boolean = false;
		
		private var connection:LocalConnection;
		private var nextReconnectTime:int = 0;
		
		public function LocalConnectionAppender() {
			super();
		}
		
		public function set connectionName (value:String) : void {
			_connectionName = value;
		}
		
		/**
		 * The name of LocalConnection object, receiver must use the same name. The default is _loggerConnection.
		 */
		public function get connectionName () : String {
			return _connectionName;
		}
		
		public function set logStackTrace (value:Boolean) : void {
			_logStackTrace = value;
		}
		
		/**
		 * Should stack trace be logged. The default is false.
		 */
		public function get logStackTrace () : Boolean {
			return _logStackTrace;
		}

		public function set reconnectInterval (value:int) : void {
			_reconnectInterval = value;
		}
		
		/**
		 * How often we'll try to reconnect (milliseconds). The default is 10000.
		 */
		public function get reconnectInterval () : int {
			return _reconnectInterval;
		}
		
		private function createConnection():void {
			connection = new LocalConnection();
			connection.addEventListener(StatusEvent.STATUS, onConnectionStatus);
		}
		
		private function onConnectionStatus(event:StatusEvent):void {
			switch (event.level) {
				case "status":
					_lastSendSuccessful = true;
					break;
				case "error":
					_lastSendSuccessful = false;
					nextReconnectTime = getTimer() + _reconnectInterval;
					break;
			}
		}
				
		/**
		 * @private
		 */
		protected override function handleLogEvent (event:LogEvent) : void {
			if (connection == null) {
				createConnection();
			}
			if (isBelowThreshold(event.level) || (!_lastSendSuccessful && (getTimer() < nextReconnectTime))) {
				return;
			}
			
			var logMessage:Object = createLogMessage(event);
			connection.send(_connectionName, _receiverMethodName, logMessage);
		}
		
		/**
		 * @private
		 */
		protected function createLogMessage (event:LogEvent) : Object {
			var logMessage:Object = {
				"timestamp": new Date(),
				"level":event.level.toString(),
				"logger":Logger(event.target).name,
				"message":event.message
			};
			if (_logStackTrace && event.error != null) {
				logMessage["stackTrace"] = event.error.getStackTrace();				
			}
			return logMessage;
		}
		
	}
}